﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLite.Threading;

namespace NLite.Domain
{
    /// <summary>
    /// 
    /// </summary>
    public interface IUnitOfWork:IBooleanDisposable
    {
        /// <summary>
        /// 
        /// </summary>
        void Flush();
    }

    /// <summary>
    /// 
    /// </summary>
    [Contract]
    public interface IUnitOfWorkFactory
    {
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IUnitOfWork Create();
    }

    /// <summary>
    /// 
    /// </summary>
    public static class UnitOfWork
    {
        public const string CurrentUnitOfWorkKey = "CurrentUnitOfWork.Key";

        private static IUnitOfWork CurrentUnitOfWork
        {
            get { return Local.Data[CurrentUnitOfWorkKey] as IUnitOfWork; }
            set { Local.Data[CurrentUnitOfWorkKey] = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public static IUnitOfWork Current
        {
            get
            {
                var unitOfWork = CurrentUnitOfWork;
                if (unitOfWork == null)
                    return Start();//throw new InvalidOperationException("You are not in a unit of work");
                return unitOfWork;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static bool IsStarted
        {
            get { return CurrentUnitOfWork != null; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static IUnitOfWork Start()
        {
            if (CurrentUnitOfWork != null && !CurrentUnitOfWork.IsDisposed)
                throw new InvalidOperationException("You cannot start more than one unit of work at the same time.");

            var unitOfWork = ServiceLocator.Get<IUnitOfWorkFactory>().Create();
            CurrentUnitOfWork = unitOfWork;
            return unitOfWork;
        }

        /// <summary>
        /// 
        /// </summary>
        public static void Dispose()
        {
            if (CurrentUnitOfWork != null)
            {
                try
                {
                    CurrentUnitOfWork.Dispose();
                }
                finally
                {
                }
            }

            CurrentUnitOfWork = null;
        }
    }
}
